﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using CrossPlatform;
using System.Threading;
using System.Net;

namespace ControlCenterService
{
    partial class NetControlToolService : ServiceBase
    {
        private int HeartBeatSystemInterval = 12 // hours
            * 60 // minutes
            * 60 // seconds
            * 1000; // milliSeconds
        private int ConfigurationUpdateInterval =
            60 *// seconds
            1000; // milliSeconds
        private int ServicePollingDeviceInterval =
            60 *// seconds
            1000; // milliSeconds
        Timer HeartBeatTimer = null;
        Timer ConfigurationUpdateTimer = null;
        Timer ServicePollingDeviceTimer = null;
        EmailUtilities emailUtilities = new EmailUtilities();
        string smtpHost = "smtp.comcast.net";
        string destinationEmailAddressList = "DestinationEmail@DestinationDomain.com";//DestinationCellNumber@txt.att.net";
        string sourceEmailAddress = "SourceEmail@SourceDomain.com";
        DataAccess.DBMSAccess dbAccess = new DataAccess.DBMSAccess();
        SerialOverUSBTools serialUSBTool = new SerialOverUSBTools();

        string sumpPumpDataMessageBuffer = string.Empty;

        public NetControlToolService()
        {
            HeartBeatSystemInterval = dbAccess.heartbeatIntervalMilliseconds();
            ConfigurationUpdateInterval = dbAccess.ConfigurationUpdateInterval();
            ServicePollingDeviceInterval = dbAccess.ServicePollingDeviceIntervalMilliseconds();
            sourceEmailAddress = dbAccess.sourceEmailAddress();
            destinationEmailAddressList = dbAccess.destinationEmailAddressList();
            InitializeComponent();
            if (!System.Diagnostics.EventLog.SourceExists(
                CrossPlatformConstants.NetControlToolsServiceEventLogSource))
            {
                System.Diagnostics.EventLog.CreateEventSource(
                    CrossPlatformConstants.NetControlToolsServiceEventLogSource,
                    CrossPlatformConstants.NetControlToolsServiceEventLogServiceStatusLog);
            }
            eventLogMain.Source = CrossPlatformConstants.NetControlToolsServiceEventLogSource;
            eventLogMain.Log = CrossPlatformConstants.NetControlToolsServiceEventLogServiceStatusLog;

            HeartBeatTimer = new System.Threading.Timer(
                    new TimerCallback(HeartBeatTimer_Tick), null,
                    System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);

            ConfigurationUpdateTimer = new System.Threading.Timer(
                    new TimerCallback(CheckForServiceConfigurationUpdatesTimer_Tick), null,
                    System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);

            ServicePollingDeviceTimer = new System.Threading.Timer(
                    new TimerCallback(ServicePollingDeviceTimer_Tick), null,
                    System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);

            //serialUSBTool.serialPort1.DataReceived +=
            //    new System.IO.Ports.SerialDataReceivedEventHandler(serialPort1_DataReceived);

            serialUSBTool.NewMessageReceived +=
                new ControlCenterService.SerialOverUSBTools.NewMessageReceivedHandler(serialUSBTool_NewMessageReceived);
        }



        void serialUSBTool_NewMessageReceived(object sender, ControlCenterService.SerialOverUSBTools.NewMessageReceivedEventArgs EventArgsParam)
        {
            // capture the new data into local storage
            sumpPumpDataMessageBuffer += EventArgsParam.Key;


            Common.Messages messages = new Common.Messages();
            Common.CrossPlatformMessagesForSumpPump sumpMessages = new Common.CrossPlatformMessagesForSumpPump();

            // test for status message
            bool success = true;
            while (success)
            {
                int RawDistance = -88;
                int CalibratedDistance = -77;
                sumpPumpDataMessageBuffer = sumpMessages.parseSumpPumpStatusMessage(
                    sumpPumpDataMessageBuffer, ref success, ref RawDistance, ref CalibratedDistance, true);
                if (success)
                {
                    dbAccess.writeSumpPumpData(DateTime.Now, RawDistance, CalibratedDistance, serialUSBTool.receiveBuffer);
                }
            }

            // test for event message
            success = true;
            while (success)
            {
                string rawDateTimeAsString = string.Empty;
                string eventType = string.Empty;
                string eventDescription = string.Empty;
                sumpPumpDataMessageBuffer = sumpMessages.parseSumpPumpEventMessage(
                    sumpPumpDataMessageBuffer, ref success, ref rawDateTimeAsString, ref eventType, ref eventDescription, true);

                // if we found an event message, write it to the database and send an email
                if (success)
                {
                    // this is how we can get the device dateTime.  lets not rely on this being set correctly
                    DateTime deviceDateTime = DateTime.Parse(rawDateTimeAsString);
                    dbAccess.writeSumpPumpEvent(DateTime.Now, eventType, eventDescription);

                    // send the email if configured
                    if (dbAccess.emailIsConfiguredAndShouldBeSent())// !String.IsNullOrWhiteSpace(destinationEmailAddressList))
                    {
                        string sumpPumpEventSubjectLine = String.Format("Sump Pump Event '{0} from server {1}", eventType, Dns.GetHostName());
                        string sumpPumpEventMessage = String.Format("Processed at {0}" + Environment.NewLine + "'{1}'", DateTime.Now.ToLongTimeString(), eventDescription);
                        if (!emailUtilities.sendEmail(smtpHost, destinationEmailAddressList, sourceEmailAddress,
                            sumpPumpEventSubjectLine, sumpPumpEventMessage))
                        {
                            eventLogMain.WriteEntry("Failed to send email in ServicePollingDeviceTimer_Tick");
                        }
                    }
                }
            }
        }


        void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            Common.Messages messages = new Common.Messages();
            Common.CrossPlatformMessagesForSumpPump sumpMessages = new Common.CrossPlatformMessagesForSumpPump();
            int RawDistance = -88;
            int CalibratedDistance = -77;
            bool success = true;
            sumpPumpDataMessageBuffer += serialUSBTool.serialPort1.ReadExisting();
            sumpPumpDataMessageBuffer = sumpMessages.parseSumpPumpStatusMessage(
                sumpPumpDataMessageBuffer, ref success, ref RawDistance, ref CalibratedDistance, true);
            if (success)
            {
                dbAccess.writeSumpPumpData(DateTime.Now, RawDistance, CalibratedDistance, serialUSBTool.receiveBuffer);
            }
            else
            {
                dbAccess.writeSumpPumpData(DateTime.Now, -23, -45, "Failed to parse for " + serialUSBTool.receiveBuffer);
            }
        }

        private void CheckForServiceConfigurationUpdatesTimer_Tick(object state)
        {
            ConfigurationUpdateTimer.Change(
                System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            try
            {
                string configUpdateSubjectLine = String.Format("Net Control Tools Configuration was updated on {0}", Dns.GetHostName());
                string configUpdateMessage = string.Empty;

                int newHeartBeatSystemInterval = dbAccess.heartbeatIntervalMilliseconds();
                int newConfigurationUpdateInterval = dbAccess.ConfigurationUpdateInterval();
                int newServicePollingDeviceInterval = dbAccess.ServicePollingDeviceIntervalMilliseconds();

                if (newHeartBeatSystemInterval != HeartBeatSystemInterval)
                {
                    configUpdateMessage +=
                        String.Format(Environment.NewLine + "Heartbeat interval changed from {0} to {1}",
                        HeartBeatSystemInterval.ToString(), newHeartBeatSystemInterval.ToString());
                    HeartBeatSystemInterval = newHeartBeatSystemInterval;

                }

                if (newConfigurationUpdateInterval != ConfigurationUpdateInterval)
                {
                    configUpdateMessage +=
                        String.Format(Environment.NewLine + "Configuration update interval changed from {0} to {1}",
                        ConfigurationUpdateInterval.ToString(), newConfigurationUpdateInterval.ToString());
                    ConfigurationUpdateInterval = newConfigurationUpdateInterval;

                }

                if (newServicePollingDeviceInterval != ServicePollingDeviceInterval)
                {
                    configUpdateMessage +=
                        String.Format(Environment.NewLine + "Service Polling Device interval changed from {0} to {1}",
                        ServicePollingDeviceInterval.ToString(), newServicePollingDeviceInterval.ToString());
                    ServicePollingDeviceInterval = newServicePollingDeviceInterval;

                }

                // send an email if there were updates
                if (configUpdateMessage.Length > 0)
                {
                    if (!emailUtilities.sendEmail(smtpHost, destinationEmailAddressList, sourceEmailAddress,
                        configUpdateSubjectLine, configUpdateMessage))
                    {
                        eventLogMain.WriteEntry("Failed to send email in CheckForServiceConfigurationUpdatesTimer_Tick");
                    }
                }
            }
            catch (Exception)
            {
                eventLogMain.WriteEntry("Failed to send email in CheckForServiceConfigurationUpdatesTimer_Tick");
            }


            ConfigurationUpdateTimer.Change(this.ConfigurationUpdateInterval, 1);

        }

        private void HeartBeatTimer_Tick(object state)
        {
            HeartBeatTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            try
            {
                // send the email if configured
                if (dbAccess.emailIsConfiguredAndShouldBeSent())// !String.IsNullOrWhiteSpace(destinationEmailAddressList))
                {
                    string heartBeatSubjectLine = String.Format("HeartBeatTimer_Tick from {0}", Dns.GetHostName());
                    string heartBeatMessage = String.Format("Processed at {0}" + Environment.NewLine + "Configuration: Heartbeat Interval = {1}", DateTime.Now.ToLongTimeString(), HeartBeatSystemInterval.ToString());
                    if (!emailUtilities.sendEmail(smtpHost, destinationEmailAddressList, sourceEmailAddress,
                        heartBeatSubjectLine, heartBeatMessage))
                    {
                        eventLogMain.WriteEntry("Failed to send email in HeartBeatTimer_Tick");
                    }
                }
            }
            catch (Exception)
            {
                eventLogMain.WriteEntry("Failed to send email in HeartBeatTimer_Tick");
            }


            HeartBeatTimer.Change(this.HeartBeatSystemInterval, 1);

        }

        private void ServicePollingDeviceTimer_Tick(object state)
        {
            ServicePollingDeviceTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            try
            {
                Common.CrossPlatformMessagesForSumpPump sumpMessages = new Common.CrossPlatformMessagesForSumpPump();
                serialUSBTool.sendChar(Convert.ToChar(sumpMessages.messageRequestingSumpPumpStatusUpdate()));

                // send the email if configured
                if (dbAccess.emailIsConfiguredAndShouldBeSent())// !String.IsNullOrWhiteSpace(destinationEmailAddressList))
                {
                    string heartBeatSubjectLine = String.Format("ServicePollingDeviceTimer_Tick from {0}", Dns.GetHostName());
                    string heartBeatMessage = String.Format("Processed at {0}" + Environment.NewLine + "Configuration: Service polling device Interval = {1}", DateTime.Now.ToLongTimeString(), ServicePollingDeviceInterval.ToString());
                    if (!emailUtilities.sendEmail(smtpHost, destinationEmailAddressList, sourceEmailAddress,
                        heartBeatSubjectLine, heartBeatMessage))
                    {
                        eventLogMain.WriteEntry("Failed to send email in ServicePollingDeviceTimer_Tick");
                    }
                }
            }
            catch (Exception)
            {
                eventLogMain.WriteEntry("Failed to send email in ServicePollingDeviceTimer_Tick");
            }


            ServicePollingDeviceTimer.Change(this.ServicePollingDeviceInterval, 1);

        }

        protected override void OnStart(string[] args)
        {
            // TODO: Add code here to start your service.
            eventLogMain.WriteEntry("in OnStart");

            // send the email if configured
            if (dbAccess.emailIsConfiguredAndShouldBeSent())// !String.IsNullOrWhiteSpace(destinationEmailAddressList))
            {
                if (!emailUtilities.sendEmail(smtpHost, destinationEmailAddressList, sourceEmailAddress, "OnStart", "Services started at: " + DateTime.Now.ToLongTimeString()))
                {
                    eventLogMain.WriteEntry("Failed to send email in OnStart");
                }
            }
            HeartBeatTimer.Change(0, HeartBeatSystemInterval);
            ConfigurationUpdateTimer.Change(0, ConfigurationUpdateInterval);
            ServicePollingDeviceTimer.Change(0, ServicePollingDeviceInterval);
        }

        protected override void OnStop()
        {
            // TODO: Add code here to perform any tear-down necessary to stop your service.
            eventLogMain.WriteEntry("in OnStop");

            // send the email if configured
            if (dbAccess.emailIsConfiguredAndShouldBeSent())// !String.IsNullOrWhiteSpace(destinationEmailAddressList))
            {
                if (!emailUtilities.sendEmail(smtpHost, destinationEmailAddressList, sourceEmailAddress, "OnStop", "Services stopped at: " + DateTime.Now.ToLongTimeString()))
                {
                    eventLogMain.WriteEntry("Failed to send email in OnStop");
                }
            }

            HeartBeatTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            ConfigurationUpdateTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            ServicePollingDeviceTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
        }

        protected override void OnContinue()
        {
            eventLogMain.WriteEntry("in OnContinue");
            
            // send the email if configured
            if (dbAccess.emailIsConfiguredAndShouldBeSent())// !String.IsNullOrWhiteSpace(destinationEmailAddressList))
            {
                if (!emailUtilities.sendEmail(smtpHost, destinationEmailAddressList, sourceEmailAddress, "OnContinue", "Services continued at: " + DateTime.Now.ToLongTimeString()))
                {
                    eventLogMain.WriteEntry("Failed to send email in OnContinue");
                }
            }
            base.OnContinue();
            HeartBeatTimer.Change(0, HeartBeatSystemInterval);
            ConfigurationUpdateTimer.Change(0, ConfigurationUpdateInterval);
            ServicePollingDeviceTimer.Change(0, ServicePollingDeviceInterval);
        }

    }
}
